/*
  S.M.A.C.K - An operating system kernel
  Copyright (C) 2010,2011 Mattias Holm and Kristian Rietveld
  For licensing and a full list of authors of the kernel, see the files
  COPYING and AUTHORS.
*/

#include <ctype.h>
#include <stddef.h>
#include <string.h>

#include <stdio.h>

void
abort(void)
{
  /* FIXME: should exit, infinite loop for now */
  while (1);
}


static int
validchar(int c, int base)
{
  if (base <= 10) {
    if ('0' <= tolower(c) && tolower(c) < '0' + base) return 1;
    return 0;
  }

  if ('0' <= tolower(c) && tolower(c) < '0' + 10) return 1;
  if ('a' <= tolower(c) && tolower(c) < 'a' + base - 10) return 1;
  return 0;
}

static int
intfromchar(int c)
{
  if ('0' <= c && c <= '9') return tolower(c) - '0';
  return tolower(c) - 'a' + 10;
}


long
strtol(const char *restrict str, char **restrict end, int base)
{
  while (isspace(*str)) str ++; // Skip WS

  // Positive or negative
  int pn = 1;
  if (*str == '+') {
    str ++; pn = 1;
  } else if (*str == '-') {
    str ++; pn = -1;
  }

  // Get effective base
  if (*str == '0' && tolower(*(str+1)) == 'x') {
    str += 2;
    if (base == 0 || base == 16) base = 16;
    else return 0;
  } else if (*str == '0' && tolower(*(str+1)) == 'b') {
    // NOTE: 0b is an extension to the ISO version of this function
    str += 2;
    if (base == 0 || base == 2) base = 2;
    else return 0;
  } else if (*str == '0') {
    str ++;
    if (base == 0 || base == 8) base = 8;
    else return 0;
  } else if (base == 0) {
    base = 10;
  }

  long result = 0;
  while (validchar(*str, base)) {
    result *= base;
    result += intfromchar(*str);
    str ++;
  }

  if (end) *end = (char *restrict)str;

  return pn*result;
}
